package soot.dava.toolkits.base.AST.structuredAnalysis;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import soot.BooleanType;
import soot.ByteType;
import soot.CharType;
import soot.DoubleType;
import soot.FloatType;
import soot.IntType;
import soot.Local;
import soot.LongType;
import soot.PrimType;
import soot.ShortType;
import soot.SootField;
import soot.Type;
import soot.Value;
import soot.dava.DavaFlowAnalysisException;
import soot.dava.internal.AST.ASTBinaryCondition;
import soot.dava.internal.AST.ASTCondition;
import soot.dava.internal.AST.ASTIfElseNode;
import soot.dava.internal.AST.ASTIfNode;
import soot.dava.internal.AST.ASTMethodNode;
import soot.dava.internal.AST.ASTUnaryBinaryCondition;
import soot.dava.internal.AST.ASTUnaryCondition;
import soot.dava.internal.javaRep.DNotExpr;
import soot.dava.toolkits.base.AST.interProcedural.ConstantFieldValueFinder;
import soot.jimple.BinopExpr;
import soot.jimple.ConditionExpr;
import soot.jimple.DefinitionStmt;
import soot.jimple.FieldRef;
import soot.jimple.Stmt;

public class CP extends StructuredAnalysis {
	/*
	 * Constant Propagation:
	 * 
	 * Step 1: Sets of CPTuple (className, CPVariable, value) where: CPVariable
	 * contains a local or SootField
	 * 
	 * Step 2: A local or SootField has a constant value at a program point p if
	 * on all program paths from the start of the method to point p the local or
	 * Sootfield has only been assigned this constant value.
	 * 
	 * Step 3: Forward Analysis
	 * 
	 * Step 4: Intersection (See intersection method in CPFlowSet)
	 * 
	 * Step 5: See method processStatement
	 * 
	 * Step 6: out(start) = all locals set to bottom(they shouldnt be present in
	 * the initialSet all formals set to Top, all constant fields set to
	 * constant values
	 * 
	 * newInitialFlow: all locals and formals set to Top, all constant fields
	 * set to constant values remember new InitialFlow is ONLY used for input to
	 * catchBodies
	 * 
	 * Any local or field which is not in the flow set at any time is
	 * necessarily bottom
	 * 
	 * 
	 * knowing how a condition evaluates can give us useful insight to the
	 * values of variables Handle this for a == b where both a and b are
	 * primtype and special case handle it for A where A is a unary boolean
	 * condition
	 * 
	 * See following over-riden methods:
	 * 
	 * public Object processASTIfElseNode(ASTIfElseNode node,Object input)
	 * public Object processASTIfNode(ASTIfNode node,Object input) public Object
	 * processASTSwitchNode(ASTSwitchNode node,Object input)
	 */

	ArrayList<CPTuple> constantFieldTuples = null; // VariableTuples of
													// constantFields
	ArrayList<CPTuple> formals = null; // VariableTuples for formals initially
										// set to T
	ArrayList<CPTuple> locals = null; // VariableTuples for locals initially set
										// to default

	ArrayList<CPTuple> initialInput = null; // VariableTuples of constantFields,
											// locals set to 0 and formals set
											// to T

	ASTMethodNode methodNode = null;
	String localClassName = null;

	/*
	 * The start of the analysis takes place whenever this constructor is
	 * invoked
	 */
	public CP(ASTMethodNode analyze, HashMap<String, Object> constantFields,
			HashMap<String, SootField> classNameFieldNameToSootFieldMapping) {
		super();
		/*
		 * DEBUG = true; DEBUG_IF = true; DEBUG_WHILE = true; DEBUG_STATEMENTS =
		 * true;
		 */
		this.methodNode = analyze;
		localClassName = analyze.getDavaBody().getMethod().getDeclaringClass().getName();

		// Create a list of VariableValueTuples for all the constantFields
		createConstantFieldsList(constantFields, classNameFieldNameToSootFieldMapping);

		// Create the complete list of vars to go into constant propagation
		createInitialInput();

		// input to constant propagation should not be an empty flow set it is
		// the set of all constant fields, locals assigned 0 and formals
		// assigned T
		CPFlowSet initialSet = new CPFlowSet();
		Iterator<CPTuple> it = initialInput.iterator();
		while (it.hasNext())
			initialSet.add(it.next());

		// System.out.println("Initial set"+initialSet.toString());
		CPFlowSet result = (CPFlowSet) process(analyze, initialSet);
		// System.out.println("Last result :"+result.toString());
	}

	/*
	 * constant fields added with KNOWN CONSTANT VALUE formals added with TOP
	 * locals added with 0 other fields IGNORED
	 */
	public void createInitialInput() {
		initialInput = new ArrayList<CPTuple>();

		// adding constant fields
		initialInput.addAll(constantFieldTuples);

		// String className =
		// analyze.getDavaBody().getMethod().getDeclaringClass().getName();

		// adding formals
		formals = new ArrayList<CPTuple>();
		// System.out.println("Adding following formals: with TOP");
		Collection col = methodNode.getDavaBody().get_ParamMap().values();
		Iterator it = col.iterator();
		while (it.hasNext()) {
			Object temp = it.next();
			if (temp instanceof Local) {
				Local tempLocal = (Local) temp;
				if (!(tempLocal.getType() instanceof PrimType))
					continue;

				CPVariable newVar = new CPVariable(tempLocal);

				// new tuple set to top since this is a formal and we dont know
				// what value we will get into it
				CPTuple newTuple = new CPTuple(localClassName, newVar, true);
				initialInput.add(newTuple);
				formals.add(newTuple);
				// System.out.print("\t"+tempLocal.getName());
			}
		}
		// System.out.println();

		// adding locals
		List decLocals = methodNode.getDeclaredLocals();
		it = decLocals.iterator();
		locals = new ArrayList<CPTuple>();
		// System.out.println("Adding following locals with default values:");
		while (it.hasNext()) {
			Object temp = it.next();
			if (temp instanceof Local) {
				Local tempLocal = (Local) temp;
				Type localType = tempLocal.getType();

				if (!(localType instanceof PrimType))
					continue;

				CPVariable newVar = new CPVariable(tempLocal);

				// store the default value into this object
				Object value;

				// locals value is set to the default value that it can have
				// depending on its type
				if (localType instanceof BooleanType)
					value = new Boolean(false);
				else if (localType instanceof ByteType)
					value = new Integer(0);
				else if (localType instanceof CharType)
					value = new Integer(0);
				else if (localType instanceof DoubleType)
					value = new Double(0);
				else if (localType instanceof FloatType)
					value = new Float(0);
				else if (localType instanceof IntType)
					value = new Integer(0);
				else if (localType instanceof LongType)
					value = new Long(0);
				else if (localType instanceof ShortType)
					value = new Integer(0);
				else
					throw new DavaFlowAnalysisException("Unknown PrimType");

				CPTuple newTuple = new CPTuple(localClassName, newVar, value);

				/*
				 * Commenting the next line since we dont want initial Input to
				 * have any locals in it all locals are considered bottom
				 * initially
				 */
				// initialInput.add(newTuple);

				locals.add(newTuple);
				// System.out.print("\t"+tempLocal.getName());
			}// was a local
		}
		// System.out.println();
	}

	/*
	 * Uses the results of the ConstantValueFinder to create a list of
	 * constantField CPTuple
	 */
	private void createConstantFieldsList(HashMap<String, Object> constantFields,
			HashMap<String, SootField> classNameFieldNameToSootFieldMapping) {
		constantFieldTuples = new ArrayList<CPTuple>();

		Iterator<String> it = constantFields.keySet().iterator();
		// System.out.println("Adding constant fields to initial set: ");
		while (it.hasNext()) {
			String combined = it.next();

			int temp = combined.indexOf(ConstantFieldValueFinder.combiner, 0);
			if (temp > 0) {
				String className = combined.substring(0, temp);

				// String fieldName = combined.substring(temp+
				// ConstantFieldValueFinder.combiner.length());
				SootField field = classNameFieldNameToSootFieldMapping.get(combined);
				// String fieldName = field.getName();

				if (!(field.getType() instanceof PrimType)) {
					// we only care about PrimTypes
					continue;
				}

				// object type is double float long boolean or integer
				Object value = constantFields.get(combined);

				CPVariable var = new CPVariable(field);

				CPTuple newTuples = new CPTuple(className, var, value);
				constantFieldTuples.add(newTuples);
				// System.out.print("Class: "+className +
				// " Field: "+fieldName+" Value: "+value+"   ");
			} else {
				throw new DavaFlowAnalysisException("Second argument of VariableValuePair not a variable");
			}

		}
		// System.out.println("");
	}

	@Override
	public DavaFlowSet emptyFlowSet() {
		return new CPFlowSet();
	}

	/*
	 * Setting the mergetype to intersection but since we are going to have
	 * constantpropagation flow sets the intersection method for this flow set
	 * will be invoked which defines the correct semantics of intersection for
	 * the case of constant propagation
	 */
	public void setMergeType() {
		MERGETYPE = INTERSECTION;
	}

	/*
	 * newInitialFlow is invoked for the input set of the catchBodies
	 * 
	 * formals initialized to top since we dont know what has happened so far in
	 * the body locals initialized to top since we dont know what has happened
	 * so far in the method body constant fields present with their constant
	 * value since that never changes
	 */
	@Override
	public DavaFlowSet newInitialFlow() {
		CPFlowSet flowSet = new CPFlowSet();

		// formals and locals should be both initialized to top since we dont
		// know what has happened so far in the body
		ArrayList<CPTuple> localsAndFormals = new ArrayList<CPTuple>();
		localsAndFormals.addAll(formals);
		localsAndFormals.addAll(locals);

		Iterator<CPTuple> it = localsAndFormals.iterator();
		while (it.hasNext()) {
			CPTuple tempTuple = (CPTuple) it.next().clone();

			// just making sure all are set to Top
			if (!tempTuple.isTop())
				tempTuple.setTop();

			flowSet.add(tempTuple);
		}

		// constant fields should be present with their constant value since
		// that never changes
		it = constantFieldTuples.iterator();
		while (it.hasNext()) {
			flowSet.add(it.next());
		}

		return flowSet;
	}

	@Override
	public DavaFlowSet cloneFlowSet(DavaFlowSet flowSet) {
		if (flowSet instanceof CPFlowSet) {
			return ((CPFlowSet) flowSet).clone();
		} else
			throw new RuntimeException("cloneFlowSet not implemented for other flowSet types" + flowSet.toString());
	}

	/*
	 * Since we are only keeping track of constant fields now there will be no
	 * kill if we were keeping track of fields then we woul dneed to kill all
	 * non constant fields if there was an invokeExpr
	 */
	@Override
	public DavaFlowSet processUnaryBinaryCondition(ASTUnaryBinaryCondition cond, DavaFlowSet input) {
		if (!(input instanceof CPFlowSet)) {
			throw new RuntimeException("processCondition is not implemented for other flowSet types" + input.toString());
		}
		CPFlowSet inSet = (CPFlowSet) input;
		return inSet;
	}

	/*
	 * Has no effect whatsoever on the analysis
	 */
	@Override
	public DavaFlowSet processSynchronizedLocal(Local local, DavaFlowSet input) {
		if (!(input instanceof CPFlowSet)) {
			throw new RuntimeException("processSynchronized  is not implemented for other flowSet types"
					+ input.toString());
		}
		DavaFlowSet inSet = (DavaFlowSet) input;
		return inSet;

	}

	/*
	 * no effect on the analysis since we are keeping track of non constant
	 * fields only if we were tracking other fields then If the value contained
	 * an invoke expr top all non constant fields similar to as done for
	 * unarybinary condition
	 */
	@Override
	public DavaFlowSet processSwitchKey(Value key, DavaFlowSet input) {
		if (!(input instanceof CPFlowSet)) {
			throw new RuntimeException("processCondition is not implemented for other flowSet types" + input.toString());
		}
		CPFlowSet inSet = (CPFlowSet) input;
		return inSet;

	}

	/*
	 * x = expr;
	 * 
	 * expr is a constant
	 * 
	 * epr is a local (Note we are not going to worry about fieldRefs)
	 * 
	 * expr is a Unary op with neg followed by a local or field
	 * 
	 * expr is actually exp1 op expr2 ..... ( x = x+1, y = i * 3, x = 3 *0
	 * 
	 * expr contains an invokeExpr
	 */
	@Override
	public DavaFlowSet processStatement(Stmt s, DavaFlowSet input) {
		if (!(input instanceof CPFlowSet))
			throw new RuntimeException("processStatement is not implemented for other flowSet types");

		CPFlowSet inSet = (CPFlowSet) input;
		if (inSet == NOPATH)
			return inSet;

		if (!(s instanceof DefinitionStmt))
			return inSet;

		DefinitionStmt defStmt = (DefinitionStmt) s;
		// x = expr;
		// confirm that the left side is a local with a primitive type
		Value left = defStmt.getLeftOp();
		if (!(left instanceof Local && ((Local) left).getType() instanceof PrimType))
			return inSet;

		// left is a primitive primitive local
		CPFlowSet toReturn = (CPFlowSet) cloneFlowSet(inSet);

		/*
		 * KILL ANY PREVIOUS VALUE OF this local as this is an assignment
		 * Remember the returned value can be null if the element was not found
		 * or it was TOP
		 */
		Object killedValue = killButGetValueForUse((Local) left, toReturn);

		Value right = defStmt.getRightOp();

		Object value = CPHelper.isAConstantValue(right);
		if (value != null) {
			// EXPR IS A CONSTANT
			if (left.getType() instanceof BooleanType) {
				Integer tempValue = (Integer) value;
				if (tempValue.intValue() == 0)
					value = new Boolean(false);
				else
					value = new Boolean(true);
			}
			addOrUpdate(toReturn, (Local) left, value);
		} else {
			// EXPR IS NOT A CONSTANT
			handleMathematical(toReturn, (Local) left, right, killedValue);
		}
		return toReturn;
	}

	/*
	 * The returned value is the current constant associated with left.
	 * Integer/Long/Double/Float/Boolean The returned value can also be null if
	 * the element was not found or it was TOP
	 */
	public Object killButGetValueForUse(Local left, CPFlowSet toReturn) {

		for (CPTuple tempTuple : toReturn) {
			if (!(tempTuple.getSootClassName().equals(localClassName)))
				continue;

			// className is the same check if the variable is the same or not
			if (tempTuple.containsLocal()) { // remmeber the sets contain
												// constant fields also
				Local tempLocal = tempTuple.getVariable().getLocal();
				if (left.getName().equals(tempLocal.getName())) {
					// KILL THIS SUCKA!!!
					Object killedValue = tempTuple.getValue();
					tempTuple.setTop();
					return killedValue;
				}
			}
		} // going through all elements of the flow set

		// if this element was no where enter it with top
		CPVariable newVar = new CPVariable(left);

		// create the CPTuple
		// System.out.println("trying to kill something which was not present so added with TOP");
		CPTuple newTuple = new CPTuple(localClassName, newVar, false);
		toReturn.add(newTuple);
		return null;
	}

	/*
	 * Create a CPTuple for left with the val and update the toReturn set
	 */
	private void addOrUpdate(CPFlowSet toReturn, Local left, Object val) {
		CPVariable newVar = new CPVariable(left);

		CPTuple newTuple = new CPTuple(localClassName, newVar, val);
		toReturn.addIfNotPresent(newTuple);
		// System.out.println("DefinitionStmt checked right expr for constants"+toReturn.toString());
	}

	/*
	 * x = b where b is in the before set of the statement as a constant then we
	 * can simply say x = that constant also
	 * 
	 * TODO: DONT WANT TO DO IT:::: If right expr is a unary expression see if
	 * the stuff inside is a Local
	 * 
	 * x = exp1 op exp2 (check if both exp1 and exp2 are int constants
	 * 
	 * killedValuse is either the constant value which left had before this
	 * assignment stmt or null if left was Top or not in the set
	 * 
	 * handle the special case when the inputset could not find a value because
	 * its the killed value //eg. x = x+1 since we top x first we will never get
	 * a match IMPORTANT
	 */
	private void handleMathematical(CPFlowSet toReturn, Local left, Value right, Object killedValue) {

		// if right expr is a local or field
		Object value = isANotTopConstantInInputSet(toReturn, right);
		if (value != null) {
			// right was a local or field with a value other than top
			// dont send value SEND A CLONE OF VALUE.....IMPORTANT!!!!
			Object toSend = CPHelper.wrapperClassCloner(value);

			if (toSend != null) {
				addOrUpdate(toReturn, left, toSend);
			}

			// return if value was != null as this means that the left was a
			// primitive local assigned some value from the right
			return;
		}

		// if we get here we know that right is not a local or field whose value
		// we could find in the set
		if (right instanceof BinopExpr) {
			Value op1 = ((BinopExpr) right).getOp1();
			Value op2 = ((BinopExpr) right).getOp2();

			Object op1Val = CPHelper.isAConstantValue(op1);
			Object op2Val = CPHelper.isAConstantValue(op2);

			if (op1Val == null)
				op1Val = isANotTopConstantInInputSet(toReturn, op1);

			if (op2Val == null)
				op2Val = isANotTopConstantInInputSet(toReturn, op2);

			if (op1 == left) {
				// System.out.println("\n\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>OP1 is the same as LHS");
				op1Val = killedValue;
			}

			if (op2 == left) {
				// System.out.println("\n\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>OP2 is the same as LHS");
				op2Val = killedValue;
			}

			if (op1Val != null && op2Val != null) {
				// System.out.println("found constant values for both operands of binary expression");
				if (left.getType() instanceof IntType && op1Val instanceof Integer && op2Val instanceof Integer) {
					// only caring about operations on two integers and result
					// is an integer

					int op1IntValue = ((Integer) op1Val).intValue();
					int op2IntValue = ((Integer) op2Val).intValue();

					String tempStr = ((BinopExpr) right).getSymbol();
					if (tempStr.length() > 1) {
						char symbol = tempStr.charAt(1);
						// System.out.println("found symbol "+symbol+" for the operands of binary expression");
						int newValue = 0;
						boolean set = false;
						switch (symbol) {
						case '+':
							// System.out.println("Adding");
							newValue = op1IntValue + op2IntValue;
							set = true;
							break;
						case '-':
							// System.out.println("Subtracting");
							newValue = op1IntValue - op2IntValue;
							set = true;

							break;

						case '*':
							// System.out.println("Multiplying");
							newValue = op1IntValue * op2IntValue;
							set = true;

							break;
						}

						if (set) {
							// we have our new value
							Integer newValueObject = new Integer(newValue);
							addOrUpdate(toReturn, left, newValueObject);
							return;
						}
					}
				}
			} else {
				// System.out.println("atleast one value is not constant so cant simplify expression");
			}
		}
		// System.out.println("DefinitionStmt checked right expr for mathematical stuff"+toReturn.toString());
	}

	/*
	 * Check whether it is a local or field which has a constant value (could be
	 * top) in the current inSet
	 * 
	 * The method returns null if its not found or its TOP Otherwise it will
	 * return the constant value
	 */
	private Object isANotTopConstantInInputSet(CPFlowSet set, Value toCheck) {
		if (toCheck instanceof Local || toCheck instanceof FieldRef) {
			String toCheckClassName = null;
			if (toCheck instanceof Local)
				toCheckClassName = localClassName;
			else
				toCheckClassName = ((FieldRef) toCheck).getField().getDeclaringClass().getName();

			for (CPTuple tempTuple : set) {
				// check that the classNames are the same
				if (!(tempTuple.getSootClassName().equals(toCheckClassName))) {
					// classNames are not the same no point in continuing with
					// checks
					continue;
				}

				boolean tupleFound = false;
				if (tempTuple.containsLocal() && toCheck instanceof Local) {
					// check they are the same Local
					Local tempLocal = tempTuple.getVariable().getLocal();
					if (tempLocal.getName().equals(((Local) toCheck).getName())) {
						// the set does have a constant value for this local
						tupleFound = true;
					}
				} else if (tempTuple.containsField() && toCheck instanceof FieldRef) {
					SootField toCheckField = ((FieldRef) toCheck).getField();
					SootField tempField = tempTuple.getVariable().getSootField();

					if (tempField.getName().equals(toCheckField.getName())) {
						// the set contains a constant value for this field
						tupleFound = true;
					}
				}

				if (tupleFound) {
					if (tempTuple.isTop())
						return null;
					else
						return tempTuple.getValue();
				}
			}

		}
		return null;
	}

	/*
	 * over-riding the StructuredFlow Analysis implementation because we want to
	 * be able to gather information about the truth value in the condition
	 */
	@Override
	public DavaFlowSet processASTIfNode(ASTIfNode node, DavaFlowSet input) {
		if (DEBUG_IF)
			System.out.println("Processing if node using over-ridden process if method" + input.toString());
		;

		input = processCondition(node.get_Condition(), input);

		if (!(input instanceof CPFlowSet)) {
			throw new DavaFlowAnalysisException("not a flow set");
		}

		CPFlowSet inputToBody = ((CPFlowSet) input).clone();

		CPTuple tuple = checkForValueHints(node.get_Condition(), inputToBody, false);

		if (tuple != null) {
			// if not null, is a belief going into the if branch simply add it
			// into the input set
			// System.out.println(">>>>>Adding tuple because of condition"+tuple.toString());
			inputToBody.addIfNotPresentButDontUpdate(tuple);
		}

		DavaFlowSet output1 = processSingleSubBodyNode(node, inputToBody);

		if (DEBUG_IF)
			System.out.println("\n\nINPUTS TO MERGE ARE input (original):" + input.toString()
					+ "processingBody output:" + output1.toString() + "\n\n\n");

		// merge with input which tells if the cond did not evaluate to true
		DavaFlowSet output2 = merge(input, output1);

		// handle break
		String label = getLabel(node);

		DavaFlowSet temp = handleBreak(label, output2, node);

		if (DEBUG_IF)
			System.out.println("Exiting if node" + temp.toString());
		;

		return temp;
	}

	@Override
	public DavaFlowSet processASTIfElseNode(ASTIfElseNode node, DavaFlowSet input) {
		if (DEBUG_IF)
			System.out.println("Processing IF-ELSE node using over-ridden process if method" + input.toString());
		;

		if (!(input instanceof CPFlowSet)) {
			throw new DavaFlowAnalysisException("not a flow set");
		}

		// get the subBodies
		List<Object> subBodies = node.get_SubBodies();
		if (subBodies.size() != 2) {
			throw new RuntimeException("processASTIfElseNode called with a node without two subBodies");
		}
		// we know there is only two subBodies
		List subBodyOne = (List) subBodies.get(0);
		List subBodyTwo = (List) subBodies.get(1);

		// process Condition
		input = processCondition(node.get_Condition(), input);

		// the current input flowset is sent to both branches
		DavaFlowSet clonedInput = cloneFlowSet(input);

		CPTuple tuple = checkForValueHints(node.get_Condition(), (CPFlowSet) clonedInput, false);
		if (tuple != null) {
			// if not null, is a belief going into the if branch simply add it
			// into the input set
			// System.out.println(">>>>>Adding tuple because of condition into if branch"+tuple.toString());
			((CPFlowSet) clonedInput).addIfNotPresentButDontUpdate(tuple);
		}

		DavaFlowSet output1 = process(subBodyOne, clonedInput);
		clonedInput = cloneFlowSet(input);
		CPTuple tuple1 = checkForValueHints(node.get_Condition(), (CPFlowSet) clonedInput, true);

		if (tuple1 != null) {
			// if not null, is a belief going into the else branch simply add it
			// into the input set
			// System.out.println(">>>>>Adding tuple because of condition  into else branch"+tuple1.toString());
			((CPFlowSet) clonedInput).addIfNotPresentButDontUpdate(tuple1);
		}
		DavaFlowSet output2 = process(subBodyTwo, clonedInput);

		if (DEBUG_IF) {

			System.out.println("\n\n  IF-ELSE   INPUTS TO MERGE ARE input (if):" + output1.toString() + " else:"
					+ output2.toString() + "\n\n\n");
		}
		DavaFlowSet temp = merge(output1, output2);

		// notice we handle breaks only once since these are breaks to the same
		// label or same node
		String label = getLabel(node);
		output1 = handleBreak(label, temp, node);
		if (DEBUG_IF) {
			System.out.println("Exiting ifelse node" + output1.toString());
			;
		}

		return output1;

	}

	/*
	 * The isElseBranch flag is true if the caller is the else branch of the
	 * ifelse statement. In that case we might be able to send something for the
	 * else branch
	 */
	public CPTuple checkForValueHints(ASTCondition cond, CPFlowSet input, boolean isElseBranch) {
		if (cond instanceof ASTUnaryCondition) {
			// check for lone boolean if(notDone)
			ASTUnaryCondition unary = (ASTUnaryCondition) cond;
			Value unaryValue = unary.getValue();

			boolean NOTTED = false;
			// Get the real value if this is a notted expression
			if (unaryValue instanceof DNotExpr) {
				unaryValue = ((DNotExpr) unaryValue).getOp();
				NOTTED = true;
			}

			if (!(unaryValue instanceof Local)) {
				// since we only track locals we cant possibly add info to the
				// inset
				return null;
			}

			// the unary value is a local add the value to the inset which woul
			// dbe present in the if branch
			CPVariable variable = new CPVariable((Local) unaryValue);

			// since NOTTED true means the if branch has variable with value
			// false and vice verse
			if (!isElseBranch) {
				// we are in the if branch hence notted true would mean the
				// variable is actually false here
				Boolean boolVal = new Boolean(!NOTTED);
				return new CPTuple(localClassName, variable, boolVal);
			} else {
				// in the else branch NOTTED true means the variable is true
				Boolean boolVal = new Boolean(NOTTED);
				return new CPTuple(localClassName, variable, boolVal);
			}
		} else if (cond instanceof ASTBinaryCondition) {
			ASTBinaryCondition binary = (ASTBinaryCondition) cond;
			ConditionExpr expr = binary.getConditionExpr();

			Boolean equal = null;

			String symbol = expr.getSymbol();
			if (symbol.indexOf("==") > -1) {
				// System.out.println("!!!!!!!!!1 FOUND == in binary comparison operaiton");
				equal = new Boolean(true);
			} else if (symbol.indexOf("!=") > -1) {
				equal = new Boolean(false);
				// System.out.println("!!!!!!!!!!!!!! FOUND != in binary comparison operaiton");
			} else {
				// a symbol we are not interested in
				// System.out.println("symbol is"+symbol);
				return null;
			}

			// we have a comparison the truth value of equal tells whether we
			// are doing == or !=
			Value a = expr.getOp1();
			Value b = expr.getOp2();

			// see if its possible to deduce a hint from these values
			CPTuple tuple = createCPTupleIfPossible(a, b, input);

			// if the tuple is not created
			if (tuple == null)
				return null;

			// we have to make sure is that the == and != are taken into account
			if (equal.booleanValue()) {
				// using equality comparison a == b this then means in the if
				// branch a is in fact equal to b
				if (!isElseBranch)
					return tuple;
				else
					return null;
			} else {
				if (isElseBranch)
					return tuple;
				else
					return null;
			}

		}
		return null;
	}

	/*
	 * Should create the final tuple to add
	 * 
	 * a == b
	 * 
	 * case 1 a is constant b is constant dont give a damm case 2 a is constant
	 * b is a local useful case 3 a is a local b is a constant useful case 4 a
	 * is a local or sootfield b is a local or sootfield useful if one of them
	 * is in the inset
	 */
	public CPTuple createCPTupleIfPossible(Value a, Value b, CPFlowSet input) {
		Object aVal = CPHelper.isAConstantValue(a);
		Object bVal = CPHelper.isAConstantValue(b);

		if (aVal != null && bVal != null) {
			// both are constants dont want to do anything..case 1
			return null;
		}

		CPVariable cpVar = null;
		Object constantToUse = null;

		if (aVal == null && bVal == null) {
			// both are not constants but one of their values could be known in
			// the inset ... case 4
			// System.out.println("a:"+a+" is not a constant b:"+b+" is not");

			// check the input set to see if either a or b have known beliefs.
			// its useful if one and only one of the two has a known belief
			Object av1 = isANotTopConstantInInputSet(input, a);
			Object av2 = isANotTopConstantInInputSet(input, b);
			if (av1 == null && av2 == null) {
				// either top or not present hence useless
				return null;
			} else if (av1 == null && av2 != null) {
				// no value of a found but value of b was found <classname, a,b>
				// System.out.println("From INSET: a:"+a+" is not a constant b "+b+" is"
				// );
				if (!(a instanceof Local && ((Local) a).getType() instanceof PrimType)) {
					// we only hanlde primitive locals
					return null;
				}
				cpVar = new CPVariable((Local) a);
				constantToUse = av2;
			} else if (av1 != null && av2 == null) {
				// no value of b found but value of a was found <classname, b,a>
				// System.out.println("From INSET: a:"+a+" is a constant b "+b+" is not"
				// );
				if (!(b instanceof Local && ((Local) b).getType() instanceof PrimType)) {
					// we only hanlde primitive locals
					return null;
				}
				cpVar = new CPVariable((Local) b);
				constantToUse = av1;
			}
		} else if (aVal != null && bVal == null) {
			// CASE 2: a is a constant and b is not so we have a chance of
			// entering a tuple <className,b,a> maybe
			// System.out.println("a:"+a+" is a constant b:"+b+" is not");

			if (!(b instanceof Local && ((Local) b).getType() instanceof PrimType)) {
				// we only hanlde primitive locals
				return null;
			}

			// able to create cpVar
			cpVar = new CPVariable((Local) b);
			constantToUse = aVal;
		} else if (aVal == null && bVal != null) {
			// CASE 3: a is not a constant but b is a constant so we have a
			// chance of entering a tuple <className,a,b>
			// System.out.println("a:"+a+" is not a constant b:"+b+" is ");

			if (!(a instanceof Local && ((Local) a).getType() instanceof PrimType)) {
				// we only hanlde primitive locals
				return null;
			}

			// able to create cpVar
			cpVar = new CPVariable((Local) a);
			constantToUse = bVal;

		}

		// if cpVar is not null and constantToUse is not null thats good
		if (cpVar != null && constantToUse != null) {
			// create a CPTuple which contains the belief for cpVar with
			// constantToUse we will for sure have going into the if branch
			// we know cpVar is always a local since we create it only for
			// locals

			// need to see if constant is supposed to be a boolean
			// (isAConstantValue returns an Integer for a boolean)
			if (cpVar.getLocal().getType() instanceof BooleanType) {
				if (!(constantToUse instanceof Integer)) {
					// booleans are represented by Integeres in the
					// isConstantValue method what happened here???
					return null;
				}

				Integer tempValue = (Integer) constantToUse;
				if (tempValue.intValue() == 0)
					constantToUse = new Boolean(false);
				else
					constantToUse = new Boolean(true);
			}

			// ready to create the CPTuple

			return new CPTuple(localClassName, cpVar, constantToUse);
		}
		return null;
	}

	/*
	 * TODO some other time
	 * 
	 * public Object processASTSwitchNode(ASTSwitchNode node,Object input){
	 * 
	 * }
	 */

}